package com.hsyt.pfc.redis.list;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;

/**
 * @Description: redis list 操作接口
 * @ClassName: RedisListHandler
 * @Package: com.hsyt.pfc.redis.list
 * @Author: wangze@hsyuntai.com
 * @Date: 2018/8/10 11:43
 * @Copyright: 版权归 HSYUNTAI 所有
 */
@Component
public class RedisListHandler {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static StringRedisTemplate stringRedisTemplate;

    @PostConstruct
    private void init() {
        stringRedisTemplate = this.redisTemplate;
    }

    public StringRedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * @Description: List（列表） ： 将一个或多个值 value 插入到列表 key 的表头
     * 							如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头： 比如说，对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ，
     * 							这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
     * 							如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作。
     * @param key
     * @param values
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:17:21
     */
    public static long lPush(final String key, String... values) {
        return stringRedisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * @Description: List（列表） ： 将一个或多个值 value 插入到列表 key 的表头
     * 							如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头： 比如说，对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ，
     * 							这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。
     * 							如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作。
     * @param key
     * @param values
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月14日 下午3:16:44
     */
    public static long lPush(final String key, Collection<String> values) {
        return stringRedisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * @Description: List（列表） ： 移除并返回列表 key 的头元素。
     * @param key
     * @return  列表的头元素。 当 key 不存在时，返回 nil 。
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:17:40
     */
    public static String lPop(final String key) {
        return stringRedisTemplate.opsForList().leftPop(key);
    }

    /**
     * @Description: List（列表） ： 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
     * 							如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表尾：比如对一个空列表 mylist 执行 RPUSH mylist a b c ，
     * 							得出的结果列表为 a b c ，	等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
     * 							 如果 key 不存在，一个空列表会被创建并执行 RPUSH 操作。
     * @param key
     * @param values
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月14日 下午3:14:16
     */
    public static long rPush(final String key,String... values){
        return stringRedisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * @Description: List（列表） ： 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
     * 							如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表尾：比如对一个空列表 mylist 执行 RPUSH mylist a b c ，
     * 							得出的结果列表为 a b c ，	等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
     * 							 如果 key 不存在，一个空列表会被创建并执行 RPUSH 操作。
     * @param key
     * @param values
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月14日 下午3:14:16
     */
    public static long rPush(final String key,Collection<String> values){
        return stringRedisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * @Description: List（列表） ： 移除并返回列表 key 的尾元素。
     * @param key
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月14日 下午3:12:07
     */
    public static String rPop(final String key){
        return stringRedisTemplate.opsForList().rightPop(key);
    }


    /**
     * @Description: List（列表） ： 返回列表 key 的长度。
     * 							如果 key 不存在，则 key 被解释为一个空列表，返回 0 .
     * @param key
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:18:16
     */
    public static long lLen(final String key) {
        return stringRedisTemplate.opsForList().size(key);
    }

    /**
     * @Description: Set（集合）：返回集合key的长度，如果 key 不存在，则 key 被解释为一个空列表，返回 0 .
     * @Author: qintao@hsyuntai.com
     * @Date: 2017/7/10 15:33
     * @Copyright: 版权归 hsyuntai 所有
     */
    public static long sLen(final String key) {
        return stringRedisTemplate.opsForSet().size(key);
    }

    /**
     * @Description: List（列表） ： 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。
     * 							  下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 							 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * 							【注意LRANGE命令和编程语言区间函数的区别】假如你有一个包含一百个元素的列表，对该列表执行 LRANGE list 0 10 ，结果是一个包含11个元素的列表，这表明 stop 下标也在 LRANGE 命令的取值范围之内(闭区间)，这和某些语言的区间函数可能不一致，
     * 							比如Ruby的 Range.new 、 Array#slice 和Python的 range() 函数。
     * 							【超出范围的下标】超出范围的下标值不会引起错误。如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大，那么 LRANGE 返回一个空列表。如果 stop 下标比 end 下标还要大，Redis将 stop 的值设置为 end 。
     * @param key
     * @param start
     * @param stop
     * @return
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:19:03
     */
    public static List<String> lRange(final String key, int start, int stop) {
        return stringRedisTemplate.opsForList().range(key, start, stop);
    }

    /**
     * @Description: List（列表） ： 根据参数 count 的值，移除列表中与参数 value 相等的元素。
     * 							 count 的值可以是以下几种：
     * 								count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
     * 								count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
     * 								count = 0 : 移除表中所有与 value 相等的值。
     * @param key
     * @param count
     * @param value
     * @return  被移除元素的数量,因为不存在的 key 被视作空表(empty list)，所以当 key 不存在时， LREM 命令总是返回 0 。
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:19:11
     */
    public static long lRem(final String key, long count, String value) {
        return stringRedisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * @Description: List（列表）： 返回列表 key 中，下标为 index 的元素。
     * 							 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 							 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * 							如果 key 不是列表类型，返回一个错误。
     * @param key
     * @param index
     * @return 列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range)，返回 nil 。
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:19:18
     */
    public static String lIndex(final String key, long index) {
        return stringRedisTemplate.opsForList().index(key, index);
    }

    /**
     * @Description: List（列表）： 将列表 key 下标为 index 的元素的值设置为 value 。
     * 							 当 index 参数超出范围，或对一个空列表( key 不存在)进行 LSET 时，返回一个错误。
     * @param key
     * @param index
     * @param value
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:19:36
     */
    public static void lSet(final String key, long index, String value) {
        stringRedisTemplate.opsForList().set(key, index, value);
    }

    /**
     * @Description: List（列表）: 对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。
     * 							 举个例子，执行命令 LTRIM list 0 2 ，表示只保留列表 list 的前三个元素，其余元素全部删除。
     * 							下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 							你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * @param key
     * @param start
     * @param end
    * @Author: wangze@hsyuntai.com
     * @Date: 2015年11月13日 上午11:19:47
     */
    public static void lTrim(final String key, long start, int end) {
        stringRedisTemplate.opsForList().trim(key, start, end);
    }

}
